﻿using UnityEngine;
using UnityEditor;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections.Generic;

 
 
public class BFImporter : AssetPostprocessor
{
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        foreach (string str in importedAssets)
        {
            //Debug.Log("Reimported Asset: " + str);
            DoImportBitmapFont(str);
        }
        foreach (string str in deletedAssets)
        {
            //Debug.Log("Deleted Asset: " + str);
            DelBitmapFont(str);
        }

        for (var i = 0; i < movedAssets.Length; i++)
        {
            //Debug.Log("Moved Asset: " + movedAssets[i] + " from: " + movedFromAssetPaths[i]);
            MoveBitmapFont(movedFromAssetPaths[i], movedAssets[i]);
        }
    }

    public static bool IsFnt(string path)
    {
        return path.EndsWith(".fnt", StringComparison.OrdinalIgnoreCase);
    }

    public static void DoImportBitmapFont(string fntPath)
    {
        if (!IsFnt(fntPath)) return;

        TextAsset fnt = AssetDatabase.LoadMainAssetAtPath(fntPath) as TextAsset;
        string text = fnt.text;
        FntParse parse = FntParse.GetFntParse(ref text);
        if (parse == null) return;

        string fntName = Path.GetFileNameWithoutExtension(fntPath);
        string rootPath = Path.GetDirectoryName(fntPath);
        string fontPath = string.Format("{0}/{1}.fontsettings", rootPath, fntName);
        Texture2D[] textures = DoImportTextures(parse, rootPath, fnt);
        if (textures.Length > 1)
        {
            Debug.LogError(fntPath + " has more than one texture!");
        }

        Font font = AssetDatabase.LoadMainAssetAtPath(fontPath) as Font;
        if (font == null)
        {
            font = new Font();
            AssetDatabase.CreateAsset(font, fontPath);
            AssetDatabase.WriteImportSettingsIfDirty(fontPath);
            AssetDatabase.ImportAsset(fontPath);
        }
        Material material = AssetDatabase.LoadAssetAtPath(fontPath, typeof(Material)) as Material;
        if (material == null)
        {
            material = new Material(Shader.Find("UI/Default"));
            material.name = "Font Material";
            AssetDatabase.AddObjectToAsset(material, fontPath);
            // unity 5.4+ cannot refresh it immediately, must import it
            AssetDatabase.ImportAsset(fontPath);
        }
        font.material = material;
        material.mainTexture = textures[0];
        font.characterInfo = parse.charInfos;

        SerializedObject so = new SerializedObject(font);
        so.Update();
        so.FindProperty("m_FontSize").floatValue = Mathf.Abs(parse.fontSize);
        so.FindProperty("m_LineSpacing").floatValue = parse.lineHeight;
        so.FindProperty("m_Ascent").floatValue = parse.lineBaseHeight;
        SerializedProperty prop = so.FindProperty("m_Descent");
        if (prop != null)
            prop.floatValue = parse.lineBaseHeight - parse.lineHeight;
        UpdateKernings(so, parse.kernings);
        so.ApplyModifiedProperties();
        so.SetIsDifferentCacheDirty();

        AssetDatabase.DeleteAsset(fntPath);
        AssetDatabase.SaveAssets();

 
        // unity 5.5 can not load custom font
        ReloadFont(fontPath);
 
    }

    private static Texture2D[] DoImportTextures(FntParse parse, string rootPath, TextAsset fnt)
    {
        int len = parse.textureNames.Length;
        Texture2D[] textures = new Texture2D[len];
        for (int i = 0; i < len; i++)
        {
            string texPath = string.Format("{0}/{1}", rootPath, parse.textureNames[i]);

            Texture2D texture = AssetDatabase.LoadMainAssetAtPath(texPath) as Texture2D;
            if (texture == null)
            {
                Debug.LogErrorFormat(fnt, "{0}: not found '{1}'.", typeof(BFImporter), texPath);
                return textures;
            }

            TextureImporter texImporter = AssetImporter.GetAtPath(texPath) as TextureImporter;
            texImporter.textureType = TextureImporterType.GUI;
            texImporter.mipmapEnabled = false;
            texImporter.SaveAndReimport();
            textures[i] = texture;
        }
        return textures;
    }

    private static void UpdateKernings(SerializedObject so, Kerning[] kernings)
    {
        int len = kernings != null ? kernings.Length : 0;
        SerializedProperty kerningsProp = so.FindProperty("m_KerningValues");

        if (len == 0)
        {
            kerningsProp.ClearArray();
            return;
        }

        int propLen = kerningsProp.arraySize;
        for (int i = 0; i < len; i++)
        {
            if (propLen <= i)
            {
                kerningsProp.InsertArrayElementAtIndex(i);
            }

            SerializedProperty kerningProp = kerningsProp.GetArrayElementAtIndex(i);
            kerningProp.FindPropertyRelative("second").floatValue = kernings[i].amount;
            SerializedProperty pairProp = kerningProp.FindPropertyRelative("first");
            pairProp.Next(true);
            pairProp.intValue = kernings[i].first;
            pairProp.Next(false);
            pairProp.intValue = kernings[i].second;
        }
        for (int i = propLen - 1; i >= len; i--)
        {
            kerningsProp.DeleteArrayElementAtIndex(i);
        }
    }

    private static void DelBitmapFont(string fntPath)
    {
        if (!IsFnt(fntPath)) return;

        string fontPath = fntPath.Substring(0, fntPath.Length - 4) + ".fontsettings";
        AssetDatabase.DeleteAsset(fontPath);
    }

    private static void MoveBitmapFont(string oldFntPath, string nowFntPath)
    {
        if (!IsFnt(nowFntPath)) return;

        string oldFontPath = oldFntPath.Substring(0, oldFntPath.Length - 4) + ".fontsettings";
        string nowFontPath = nowFntPath.Substring(0, nowFntPath.Length - 4) + ".fontsettings";
        AssetDatabase.MoveAsset(oldFontPath, nowFontPath);
    }

    // new font can not display via Text in unity 5.5
    // must import import it
    private static void ReloadFont(string fontPath)
    {
        var tmpPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
        AssetDatabase.ExportPackage(fontPath, tmpPath);
        AssetDatabase.DeleteAsset(fontPath);

        var startTime = DateTime.Now;
        EditorApplication.CallbackFunction func = null;
        func = () =>
        {
            TimeSpan dalt = DateTime.Now - startTime;
            if (dalt.TotalSeconds >= 0.1)
            {
                EditorApplication.update -= func;
                AssetDatabase.ImportPackage(tmpPath, false);
                File.Delete(tmpPath);
            }
        };

        EditorApplication.update += func;
    }
}
 
